home *** CD-ROM | disk | FTP | other *** search
- {---------------------------------------------------------}
- { Unit : Dbase III Access Routines }
- { Auteur : Ir. G.W. van der Vegt }
- { Hondsbroek 57 }
- { 6121 XB Born }
- {---------------------------------------------------------}
- { Datum .tijd Revisie }
- { 910701.2130 Creatie. }
- { 910702.1000 Minor Errors Corrected }
- { Replace, Append & Pack Added }
- { 910706.2400 dbrec on the Heap (recsize max 64kB-16) }
- { Uppercase Conversion in Bd3_fileno }
- { Optional Halt on (fatal) Errors }
- { 910710.1500 Memo Field Support }
- { 910715.2330 Field2num bug fixed (leading sp. removed) }
- { 910960.1130 Fieldno Out of range detection }
- { 920116.1000 Two minor bugs fixed }
- { 920124.2200 Header updated when file is closed, }
- { Db3_Seekbof & Db3_Seekeof added }
- { Db3_Findfirst & Db3_Findnext implemented }
- { for wildcard search of records }
- { Db3_soudex & Db3_field2soundex for Soundex}
- { code (sound alike) operations }
- { Db3_firstsoudex & Db3_nextsoundex for }
- { soundex search on a field }
- { 920127.1300 Dbase Slack Filespace Detection & }
- { Correction }
- { 920129.2115 Trailing spaces remover in Db3_field2str }
- { Seek after truncate in Db3_open }
- { 920130.2145 Slack filespace bug removed }
- { Db3_sort implemented (based on shakersort)}
- { Bug in Db3_date2field removed }
- { 920716.2130 Empty file pack fixed in Db3_pack }
- { 920928.2200 Obscure bug in Db3_fieldname. Fieldnames }
- { seem to be are ASCIZ in stead of fixed }
- { length strings. }
- { 930927.2000 Freemem bug in db3_findnext corrected. }
- {---------------------------------------------------------}
- { To Do Full Documentation }
- { Write Memo Support }
- { Extend Db3_pack with MemoFile Packing }
- { Sort *.DBF in place }
- { Insert record in *.DBF file }
- { Date format not always yy-mm-dd }
- {---------------------------------------------------------}
-
- UNIT Db3_01;
-
- INTERFACE
-
- USES
- DOS;
-
- {---------------------------------------------------------}
- {----Error Handling : Returns First Error Which Occured }
- {---------------------------------------------------------}
-
- VAR
- db3_ernr : INTEGER; {----DB3 Module Error Code}
- db3_fatal : BOOLEAN; {----IF True
- THEN Halt(db3_ernr)
- on an error}
-
- db3_memotext : TEXT; {----Memo File}
-
- {---------------------------------------------------------}
-
- FUNCTION Db3_ermsg(nr : INTEGER) : STRING;
-
- {---------------------------------------------------------}
- {----Initialize/Exit : Must both be Called for every file }
- {---------------------------------------------------------}
-
- PROCEDURE Db3_open(fn : STRING); {----Opens fn.DBF file &
- Inits Internals}
- PROCEDURE Db3_close; {----Closes fn.DBF file}
-
- {---------------------------------------------------------}
- {----Header Function : Get .DBF header info }
- {---------------------------------------------------------}
-
- FUNCTION Db3_memo : BOOLEAN;
-
- FUNCTION Db3_update : STRING;
-
- FUNCTION Db3_norecs : LONGINT;
-
- FUNCTION Db3_nofields : INTEGER;
-
- FUNCTION Db3_reclen : INTEGER;
-
- {---------------------------------------------------------}
- {----File I/O : Dbase III Alike (pos etc. in records) }
- {---------------------------------------------------------}
-
- PROCEDURE Db3_seek(pos : LONGINT);
-
- FUNCTION Db3_filesize : LONGINT;
-
- FUNCTION Db3_filepos : LONGINT;
-
- PROCEDURE Db3_readnext;
-
- PROCEDURE Db3_read(pos : LONGINT);
-
- PROCEDURE Db3_seekeof;
-
- PROCEDURE Db3_seekbof;
-
- FUNCTION Db3_eof : BOOLEAN;
-
- FUNCTION Db3_bof : BOOLEAN;
-
- PROCEDURE Db3_replace(no : LONGINT); {----First Read record &
- Fill all fields}
- PROCEDURE Db3_append; {----First Fill all Fields}
-
- PROCEDURE Db3_delete(no : LONGINT);
-
- PROCEDURE Db3_undelete(no : LONGINT);
-
- PROCEDURE Db3_pack; {----Packs File IN-PLACE}
-
- PROCEDURE Db3_blankrec;
-
- {---------------------------------------------------------}
- {----Field Operations : no is .DBF field number }
- {---------------------------------------------------------}
-
- FUNCTION Db3_fieldname(no : INTEGER) : STRING;
-
- FUNCTION Db3_fieldlen(no : INTEGER) : INTEGER;
-
- FUNCTION Db3_fielddec(no : INTEGER) : INTEGER;
-
- FUNCTION Db3_fieldno(name : STRING) : INTEGER; {----Searches Fieldnumber for
- Uppercase fieldname}
- FUNCTION Db3_fieldtype(no : INTEGER) : CHAR;
-
- FUNCTION Db3_deleted : BOOLEAN;
-
- {---------------------------------------------------------}
- {----Field Conversions : date format 'dd-mm-19yy' }
- {---------------------------------------------------------}
-
- FUNCTION Db3_field2str(no :INTEGER) : STRING;
-
- FUNCTION Db3_field2char(no :INTEGER) : CHAR;
-
- FUNCTION Db3_field2logic(no : INTEGER) : BOOLEAN;
-
- FUNCTION Db3_field2num(no : INTEGER) : REAL;
-
- FUNCTION Db3_field2date(no :INTEGER) : STRING;
-
- PROCEDURE Db3_field2memo(no : INTEGER);
-
- FUNCTION Db3_field2soundex(no : INTEGER) : STRING;
-
- PROCEDURE Db3_str2field(no :INTEGER;s : STRING);
-
- PROCEDURE Db3_char2field(no :INTEGER;s : CHAR);
-
- PROCEDURE Db3_logic2field(no : INTEGER;l : BOOLEAN);
-
- PROCEDURE Db3_num2field(no : INTEGER;n : REAL);
-
- PROCEDURE Db3_date2field(no :INTEGER;d : STRING);
-
- {---------------------------------------------------------}
- {----Database Search, spaces are used as wildcards. }
- { Db3_blankrec can be used for creating a wildcard }
- { record. Then if Findfirst is true the use Findnext }
- { until Findnext becomes false. After each succesfull }
- { call the internal readbuffer will contain the }
- { matching record. Use casesense=true for a case }
- { sensitive search. }
- {---------------------------------------------------------}
-
- FUNCTION Db3_findfirst(cs : BOOLEAN) : BOOLEAN;
-
- FUNCTION Db3_findnext(cs : BOOLEAN) : BOOLEAN;
-
- {---------------------------------------------------------}
- {----Soundex Code Function (sound alike) }
- {---------------------------------------------------------}
-
- FUNCTION Db3_soundex(name : STRING) : STRING;
-
- FUNCTION Db3_firstsoundex(no : INTEGER; s : STRING) : BOOLEAN;
-
- FUNCTION Db3_nextsoundex(no : INTEGER; s : STRING) : BOOLEAN;
-
- {---------------------------------------------------------}
- {----Shaker Sort Almost Sorted *.DBF Files }
- {---------------------------------------------------------}
-
- PROCEDURE Db3_sort(no : INTEGER);
-
- IMPLEMENTATION
-
- {---------------------------------------------------------}
- {----Error Handling }
- {---------------------------------------------------------}
-
- PROCEDURE Seternr(e : INTEGER);
-
- BEGIN
- IF (db3_ernr=0) THEN db3_ernr:=e;
- IF db3_fatal
- THEN
- BEGIN
- Writeln;
- Writeln('Db3_01 [Error : ',db3_ernr:0,' = '+Db3_ermsg(db3_ernr)+']');
- Writeln;
- IF (db3_ernr<>1) THEN Db3_close;
- Halt(e);
- END;
- END; {of Seternr}
-
- {---------------------------------------------------------}
-
- FUNCTION Db3_ermsg(nr : INTEGER) : STRING;
-
- BEGIN
- CASE nr OF
- 0 : Db3_ermsg:='No Error';
- 1 : Db3_ermsg:='Error Opening File';
- 2 : Db3_ermsg:='Seek Past EOF';
- 3 : Db3_ermsg:='Seek Before BOF';
- 4 : Db3_ermsg:='Read Past EOF';
- 5 : Db3_ermsg:='Invalid Numeric Field';
- 6 : Db3_ermsg:='Field Name NOT Found';
- 7 : Db3_ermsg:='Invalid Header';
- 8 : Db3_ermsg:='Incorrect Filesize';
- 9 : Db3_ermsg:='Records to Large';
- 10 : Db3_ermsg:='To many Fields';
- 11 : Db3_ermsg:='Invalid Date Format';
- 12 : Db3_ermsg:='Cannot Format Real';
- 13 : Db3_ermsg:='Record was already deleted';
- 14 : Db3_ermsg:='Record was not deleted';
- 15 : Db3_ermsg:='NOT a Dbase III File';
- 16 : Db3_ermsg:='Field Number NOT Found';
- 17 : Db3_ermsg:='No Memofields in this file';
- 18 : Db3_ermsg:='All matching records already found';
- 19 : Db3_ermsg:='No *.DBF file open';
- 20 : Db3_ermsg:='*.DBF already file open';
- 99 : Db3_ermsg:='NOT Yet Implemented';
- ELSE Db3_ermsg:='Unkown Error';
- END;
-
- db3_ernr:=0;
- END; {of Db3_ermsg}
-
- {---------------------------------------------------------}
- {----Types/Vars & Constants }
- {---------------------------------------------------------}
-
- TYPE
- dbheader = RECORD
- dbvers : BYTE;
- dbupdy,
- dbupdm,
- dbupdd : BYTE;
- dbnorec: LONGINT;
- dbheadl,
- dbrecl : INTEGER;
- dbres : ARRAY[1..20] OF BYTE;
- END;
-
- dbfield = RECORD {----Definition of Field Header}
- dbname : ARRAY[1..11] OF CHAR;
- dbtype : CHAR;
- dbadr : LONGINT;
- dblen,
- dbdec : BYTE;
- dbres : ARRAY[1..14] OF CHAR;
- END;
-
- fptr = RECORD {----Definition of Readbuf Index}
- fppos : WORD;
- fplen : BYTE;
- END;
-
- CONST
- maxfield = 60; {----Max number of Fields}
- maxsize = 65000; {----Maximum Record Size}
-
- TYPE
- rectyp = ARRAY[0..maxsize] OF CHAR; {----Record Readbuffer Type}
-
- VAR
- f : file; {----.DBF File}
-
- header : dbheader; {----Space for Header}
- nofields : INTEGER; {----Number of Fields}
-
- fields : ARRAY[1..maxfield] OF dbfield; {----Field Definitions}
- fieldptr : ARRAY[1..maxfield] OF fptr; {----Index into Readbuffer}
- recstart : LONGINT; {----Start of Record Area}
-
- dbrec : ^rectyp; {----Record Buffer}
- reclen : WORD; {----Record Length}
-
- memo : FILE; {----Memo File}
- memopos : LONGINT; {----Location of Memo Record}
- memobuf : ARRAY[1..512] OF CHAR; {----Memo Text File buffer}
-
- dbsearch : ^rectyp; {----Search Record Buffer}
-
- {---------------------------------------------------------}
- {----Initialize }
- {---------------------------------------------------------}
-
- PROCEDURE Db3_open(fn : STRING);
-
- VAR
- i : INTEGER;
- j : WORD;
- ch : CHAR;
-
- BEGIN
- IF (dbrec<>NIL)
- THEN Seternr(20)
- ELSE
- BEGIN
- Assign(f,fn+'.DBF');
- {$I-} Reset(f,1); {$I+}
- IF (Ioresult<>0)
- THEN Seternr(1)
- ELSE
- BEGIN
- {----Dump Header}
- Blockread(f,header,32);
-
- Getmem(dbrec,header.dbrecl+1);
-
- {---Scan for Fieldnames & Recordlength}
- reclen :=1;
- nofields:=0;
- Blockread(f,ch,1);
- WHILE (nofields<maxfield) AND (ch<>#13) DO
- BEGIN
- Inc(nofields);
- WITH fields[nofields] DO
- BEGIN
- dbname[1]:=ch;
- Blockread(f,dbname[2],Sizeof(dbfield)-1);
- Inc(reclen,dblen);
- Blockread(f,ch,1);
- END;
- END;
-
- IF (ch<>#13) THEN Seternr(10);
-
- {----Zapped file contains only a EOF}
- recstart:=Filepos(f);
-
- {----Set fieldptr}
- j:=1;
- FOR i:=1 TO nofields DO
- WITH fieldptr[i],fields[i] DO
- BEGIN
- fplen:=dblen;
- fppos:=j;
- Inc(j,dblen);
- END;
-
- {----Header Integrity Checks}
- IF NOT(header.dbvers IN [$03,$83]) THEN Seternr(15);
-
- IF ((header.dbheadl DIV 32)-1<>nofields) OR
- (header.dbrecl<>reclen)
- THEN Seternr(7);
-
- {----File Size Check}
- IF (header.dbnorec*reclen<>(Filesize(f)-recstart-1))
- THEN
- BEGIN
- {----Truncate DBASE Slack Filespace}
- { Writeln('Truncating'); }
- Db3_Seek(header.dbnorec+1);
- {$I-} Seek(f,Filepos(f)+1); {$I+}
- IF (IOresult=0)
- THEN Truncate(f)
- ELSE Seternr(8);
- END;
-
- IF (reclen>Sizeof(rectyp)) THEN Seternr(9);
-
- IF Db3_memo
- THEN
- BEGIN
- Assign(memo,fn+'.DBT');
- {$I-} Reset(memo,1); {$I+}
- IF (IOresult<>0) THEN Seternr(17);
- END;
-
- IF (db3_ernr<>0) THEN Freemem(dbrec,header.dbrecl+1);
- END;
-
- IF (db3_ernr<>0)
- THEN dbrec:=NIL
- ELSE Db3_Seekbof
-
- END;
- END; {of Db3_open}
-
- {---------------------------------------------------------}
-
- PROCEDURE Db3_close;
-
- VAR
- y,m,d,dow : WORD;
-
- BEGIN
- IF (dbrec<>NIL)
- THEN
- BEGIN
- {----Update *.DBF File Header}
- Getdate(y,m,d,dow);
- WITH header DO
- BEGIN
- dbupdy :=y MOD 100;
- dbupdm :=m;
- dbupdd :=d;
- dbnorec:=Db3_filesize;
- END;
- Reset(f,1);
- Blockwrite(f,header,32);
- Close(f);
-
- {----Cleanup Memory}
- Freemem(dbrec,header.dbrecl+1);
- IF dbsearch<>NIL THEN Freemem(dbsearch,header.dbrecl+1);
-
- dbrec :=NIL;
- dbsearch :=NIL;
- END
- ELSE Seternr(19);
- END; {of DB3_close}
-
- {---------------------------------------------------------}
- {----Header Operations }
- {---------------------------------------------------------}
-
- FUNCTION Db3_memo : BOOLEAN;
-
- BEGIN
- Db3_memo:=header.dbvers=$83;
- END; {of Db3_memo}
-
- {---------------------------------------------------------}
-
- FUNCTION Db3_update : STRING;
-
- VAR
- s : STRING;
-
- BEGIN
- s:='dd-mm-19yy';
- s[ 1]:=Chr(Ord('0')+header.dbupdd DIV 10);
- s[ 2]:=Chr(Ord('0')+header.dbupdd MOD 10);
- s[ 4]:=Chr(Ord('0')+header.dbupdm DIV 10);
- s[ 5]:=Chr(Ord('0')+header.dbupdm MOD 10);
- s[ 9]:=Chr(Ord('0')+header.dbupdy DIV 10);
- s[10]:=Chr(Ord('0')+header.dbupdy MOD 10);
-
- Db3_update:=s;
- END; {of Db3_update}
-
- {---------------------------------------------------------}
-
- FUNCTION Db3_norecs : LONGINT;
-
- BEGIN
- Db3_norecs:=header.dbnorec;
- END; {of Db3_norecs}
-
- {---------------------------------------------------------}
-
- FUNCTION Db3_nofields : INTEGER;
-
- BEGIN
- Db3_nofields:=nofields;
- END; {of Db3_nofields}
-
- {---------------------------------------------------------}
-
- FUNCTION Db3_reclen : INTEGER;
-
- BEGIN
- Db3_reclen:=reclen;
- END; {of Db3_reclen}
-
- {---------------------------------------------------------}
- {----File I/O }
- {---------------------------------------------------------}
-
- PROCEDURE Db3_seek(pos : LONGINT);
-
- BEGIN
- {$I-} Seek(f,recstart+(pos-1)*reclen); {$I+}
- IF (Ioresult<>0) OR (pos<1) OR (pos>Db3_filesize+1)
- THEN
- BEGIN
- IF (pos>0)
- THEN Seternr(2)
- ELSE Seternr(3);
- END;
- END; {of Db3_seek}
-
- {---------------------------------------------------------}
-
- FUNCTION Db3_filesize : LONGINT;
-
- BEGIN
- Db3_filesize:=(Filesize(f)-recstart) DIV reclen;
- END; {of Db3_filesize}
-
- {---------------------------------------------------------}
-
- FUNCTION Db3_filepos : LONGINT;
-
- BEGIN
- Db3_filepos:=((Filepos(f)-recstart) DIV reclen)+1;
- END; {of Db3_filepos}
-
- {---------------------------------------------------------}
-
- PROCEDURE Db3_readnext;
-
- BEGIN
- IF EOF(f) OR Db3_Eof
- THEN Seternr(4)
- ELSE Blockread(f,dbrec^,reclen);
- END; {of Db3_readnext}
-
- {---------------------------------------------------------}
-
- PROCEDURE Db3_read(pos : LONGINT);
-
- BEGIN
- Db3_seek(pos);
- Db3_readnext;
- END; {of Db3_read}
-
- {---------------------------------------------------------}
-
- PROCEDURE Db3_seekeof;
-
- BEGIN
- Db3_Seek(Db3_filesize+1);
- END; {of Db3_seekeof}
-
- {---------------------------------------------------------}
-
- PROCEDURE Db3_seekbof;
-
- BEGIN
- Seek(f,recstart);
- END; {of Db3_seekeof}
-
- {---------------------------------------------------------}
-
- FUNCTION Db3_eof : BOOLEAN;
-
- BEGIN
- Db3_eof:=(Filepos(f)>=Filesize(f)-1);
- END; {of Db3_eof}
-
- {---------------------------------------------------------}
-
- FUNCTION Db3_bof : BOOLEAN;
-
- BEGIN
- Db3_bof:=Filepos(f)=recstart;
- END; {of Db3_bof}
-
- {---------------------------------------------------------}
-
- PROCEDURE Db3_replace(no : LONGINT);
-
- BEGIN
- Db3_seek(no);
- IF (db3_ernr=0) THEN Blockwrite(f,dbrec^[0],reclen)
- END; {of Db3_append}
-
- {---------------------------------------------------------}
-
- PROCEDURE Db3_append;
-
- VAR
- ch : CHAR;
-
- BEGIN
- Db3_seek(Db3_filesize+1);
- Blockwrite(f,dbrec^[0],reclen);
- ch:=^Z;
- Blockwrite(f,ch,1);
- Db3_seek(Db3_filesize+1);
- END; {of Db3_append}
-
- {---------------------------------------------------------}
-
- PROCEDURE Db3_delete(no : LONGINT);
-
- BEGIN
- Db3_read(no);
- IF dbrec^[0]='*'
- THEN Seternr(13)
- ELSE dbrec^[0]:='*';
- Db3_replace(no)
- END; {of Db3_delete}
-
- {---------------------------------------------------------}
-
- PROCEDURE Db3_undelete(no : LONGINT);
-
- BEGIN
- Db3_read(no);
- IF dbrec^[0]=' '
- THEN Seternr(14)
- ELSE dbrec^[0]:=' ';
- Db3_replace(no)
- END; {of Db3_undelete}
-
- {---------------------------------------------------------}
-
- PROCEDURE Db3_pack;
-
- VAR
- i,j : LONGINT;
- ch : CHAR;
-
- BEGIN
- j:=0;
- FOR i:=1 TO Db3_filesize DO
- BEGIN
- Db3_read(i);
- IF NOT(Db3_deleted)
- THEN
- BEGIN
- Inc(j);
- Db3_replace(j)
- END
- END;
-
- {----New EOF Marker}
- IF (j=0)
- THEN db3_SeekBof
- ELSE Db3_read(j);
- ch:=^Z;
- Blockwrite(f,ch,1);
- Truncate(f);
-
- Db3_seek(1);
- END; {of Db3_pack}
-
- {---------------------------------------------------------}
-
- PROCEDURE Db3_blankrec;
-
- VAR
- i : INTEGER;
-
- BEGIN
- FOR i:=0 TO reclen-1 DO dbrec^[i]:=#32;
- END; {of Db3_blankrec}
-
- {---------------------------------------------------------}
- {----Field Operations }
- {---------------------------------------------------------}
-
- FUNCTION Db3_fieldname(no : INTEGER) : STRING;
-
- VAR
- s : STRING;
- i : WORD;
-
- BEGIN
- s:='';
- i:=1;
- IF no IN [1..nofields]
- THEN
- BEGIN
- WITH fields[no] DO
- WHILE (i<=Sizeof(dbname)) AND (dbname[i]<>#0) DO
- BEGIN
- s:=s+dbname[i];
- Inc(i);
- END;
- END
- ELSE Seternr(16);
- Db3_fieldname:=s;
- END; {of Db3_fieldname}
-
- {---------------------------------------------------------}
-
- FUNCTION Db3_fieldlen(no : INTEGER) : INTEGER;
-
- BEGIN
- Db3_fieldlen:=0;
- IF no IN [1..nofields]
- THEN Db3_fieldlen:=fields[no].dblen
- ELSE Seternr(16);
- END; {of Db3_fieldlen}
-
- {---------------------------------------------------------}
-
- FUNCTION Db3_fielddec(no : INTEGER) : INTEGER;
-
- BEGIN
- Db3_fielddec:=0;
- IF no IN [1..nofields]
- THEN Db3_fielddec:=fields[no].dbdec
- ELSE Seternr(16)
- END; {of Db3_fielddec}
-
- {---------------------------------------------------------}
-
- FUNCTION Db3_fieldno(name : STRING) : INTEGER;
-
- VAR
- i,j : INTEGER;
- s : STRING;
-
- BEGIN
- Db3_fieldno:=0;
-
- s:=name;
- FOR i:=1 TO Length(s) DO s[i]:=Upcase(s[i]);
-
- i:=1;
- WHILE (i<=nofields) AND (s<>Db3_fieldname(i)) DO
- Inc(i);
-
- IF (i>nofields)
- THEN Seternr(6)
- ELSE Db3_fieldno:=i;
- END; {of Db3_fieldno}
-
- {---------------------------------------------------------}
-
- FUNCTION Db3_fieldtype(no : INTEGER) : CHAR;
-
- BEGIN
- Db3_fieldtype:=#00;
- IF no IN [1..nofields]
- THEN Db3_fieldtype:=fields[no].dbtype
- ELSE Seternr(16);
- END; {of Db3_fieldtype}
-
- {---------------------------------------------------------}
-
- FUNCTION Db3_deleted : BOOLEAN;
-
- BEGIN
- Db3_deleted:=dbrec^[0]<>#32;
- END; {of Db3_deleted}
-
- {---------------------------------------------------------}
- {----Field Conversions }
- {---------------------------------------------------------}
-
- FUNCTION Db3_field2str(no :INTEGER) : STRING;
-
- VAR
- s : STRING;
- i : WORD;
-
- BEGIN
- s:='';
- IF (no IN [1..nofields])
- THEN
- BEGIN
- s[0]:=Chr(fieldptr[no].fplen);
- Move(dbrec^[fieldptr[no].fppos],s[1],fieldptr[no].fplen);
- END
- ELSE Seternr(16);
- {----Strip Trailing Spaces}
- WHILE (Length(s)>0) AND (s[Length(s)]=#32) DO Dec(s[0]);
- Db3_field2str:=s;
- END; {of Db3_field2str}
-
- {---------------------------------------------------------}
-
- FUNCTION Db3_field2char(no :INTEGER) : CHAR;
-
- VAR
- s : STRING;
-
- BEGIN
- IF (Db3_fieldlen(no)=1)
- THEN s:=Db3_field2str(no)
- ELSE s:=#00;
-
- IF (Length(s)=0)
- THEN Db3_field2char:=#32
- ELSE Db3_field2char:=s[1];
- END; {of Db3_field2char}
-
- {---------------------------------------------------------}
-
- FUNCTION Db3_field2logic(no : INTEGER) : BOOLEAN;
-
- BEGIN
- Db3_field2logic:=(Db3_field2char(no)='T');
- END; {of Db3_field2logic}
-
- {---------------------------------------------------------}
-
- FUNCTION Db3_field2num(no : INTEGER) : REAL;
-
- VAR
- r : REAL;
- s : STRING;
- e : INTEGER;
-
- BEGIN
- s:=Db3_field2str(no);
- WHILE (Length(s)>0) AND (s[1]=#32) DO Delete(s,1,1);
- Val(s,r,e);
- IF (e<>0)
- THEN Seternr(5);
- Db3_field2num:=r;
- END; {of Db3_field2num}
-
- {---------------------------------------------------------}
-
- FUNCTION Db3_field2date(no :INTEGER) : STRING;
-
- VAR
- s : STRING;
-
- BEGIN
- s:='dd-mm-yyyy';
- IF (no IN [1..nofields])
- THEN
- BEGIN
- Move(dbrec^[fieldptr[no].fppos+6],s[1],2);
- Move(dbrec^[fieldptr[no].fppos+4],s[4],2);
- Move(dbrec^[fieldptr[no].fppos+0],s[7],4);
- END
- ELSE Seternr(16);
-
- Db3_field2date:=s;
- END; {of Db3_field2date}
-
- {---------------------------------------------------------}
-
- FUNCTION Db3_field2soundex(no : INTEGER) : STRING;
-
- BEGIN
- Db3_field2soundex:=Db3_soundex(Db3_field2str(no));
- END; {of Db3_field2soundex}
-
- {---------------------------------------------------------}
-
- PROCEDURE Db3_str2field(no :INTEGER;s : STRING);
-
- BEGIN
- IF (no IN [1..nofields])
- THEN
- BEGIN
- Fillchar(dbrec^[fieldptr[no].fppos],fieldptr[no].fplen,#32);
- WITH fields[no] DO
- IF (Length(s)>dblen)
- THEN Move(s[1],dbrec^[fieldptr[no].fppos],dblen)
- ELSE Move(s[1],dbrec^[fieldptr[no].fppos],Length(s));
- END
- ELSE Seternr(16)
- END; {of Db3_str2field}
-
- {---------------------------------------------------------}
-
- PROCEDURE Db3_char2field(no :INTEGER;s : CHAR);
-
- BEGIN
- Db3_str2field(no,s);
- END; {of Db3_char2field}
-
- {---------------------------------------------------------}
-
- PROCEDURE Db3_logic2field(no : INTEGER;l : BOOLEAN);
-
- BEGIN
- IF l
- THEN Db3_char2field(no,'T')
- ELSE Db3_char2field(no,'F')
- END; {of Db3_logic2field}
-
- {---------------------------------------------------------}
-
- PROCEDURE Db3_num2field(no : INTEGER;n: REAL);
-
- VAR
- s : STRING;
-
- BEGIN
- IF (no IN [1..nofields])
- THEN
- BEGIN
- Str(n:fields[no].dblen:fields[no].dbdec,s);
- IF (Length(s)>fields[no].dblen)
- THEN Seternr(12)
- ELSE Db3_str2field(no,s);
- END
- ELSE Seternr(16)
- END; {of Db3_num2field}
-
- {---------------------------------------------------------}
-
- PROCEDURE Db3_date2field(no :INTEGER;d : STRING);
-
- VAR
- s : STRING;
-
- BEGIN
- IF (Length(d)<>10) OR
- (d[3]<>'-') OR
- (d[6]<>'-')
- THEN Seternr(11)
- ELSE
- BEGIN
- {----dd-mm-yyyy}
- s[1]:=d[ 7];
- s[2]:=d[ 8];
- s[3]:=d[ 9];
- s[4]:=d[10];
- s[5]:=d[ 4];
- s[6]:=d[ 5];
- s[7]:=d[ 1];
- s[8]:=d[ 2];
- Db3_str2field(no,s);
- END;
- END; {of Db3_date2field}
-
- {---------------------------------------------------------}
- {----Memo text field support }
- {---------------------------------------------------------}
-
- {$F+}
-
- FUNCTION memoignore(VAR f : textrec) : INTEGER;
-
- BEGIN
- memoignore:=0;
- END; {of memoignore}
-
- {---------------------------------------------------------}
-
- FUNCTION memoinput(VAR f : textrec) : INTEGER;
-
- VAR
- chread : WORD;
-
- BEGIN
- WITH Textrec(f) DO
- BEGIN
- Blockread(memo,memobuf[1],Sizeof(memobuf),chread);
- bufpos :=0;
- bufend :=chread;
- END;
- memoinput:=0;
- END; {of memoinput}
-
- {$F-}
-
- {---------------------------------------------------------}
-
- PROCEDURE Assignmemo(VAR f : TEXT);
-
- VAR
- chread : WORD;
-
- CONST
- fminput =$D7B1;
-
- BEGIN
- WITH Textrec(f) DO
- BEGIN
- handle :=$ffff;
- mode :=fminput;
- bufsize :=SIZEOF(memobuf);
- bufpos :=0;
- bufptr :=@memobuf;
-
- Blockread(memo,memobuf[1],Sizeof(memobuf),chread);
- bufpos :=0;
- bufend :=chread;
-
- openfunc :=@memoignore;
- inoutfunc:=@memoinput;
- flushfunc:=@memoignore;
- closefunc:=@memoignore;
- name[0] :=#00;
- END;
- END; {of Assignmemo}
-
- {---------------------------------------------------------}
-
- PROCEDURE Db3_field2memo(no : INTEGER);
-
- VAR
- e : INTEGER;
- s : STRING;
-
- BEGIN
- IF Db3_memo
- THEN
- BEGIN
- s:=Db3_field2str(no);
- WHILE (Length(s)>0) AND (s[1]=#32) DO Delete(s,1,1);
- Val(s,memopos,e);
- IF (e<>0)
- THEN Seternr(5)
- ELSE
- BEGIN
- Seek(memo,memopos*Sizeof(memobuf));
- Assignmemo(db3_memotext);
- END;
- END
- ELSE Seternr(17);
- END; {of Db3_field2memo}
-
- {---------------------------------------------------------}
-
- FUNCTION Db3_findfirst(cs : BOOLEAN) : BOOLEAN;
-
- VAR
- match,
- found : BOOLEAN;
- i : INTEGER;
-
- BEGIN
- Getmem(dbsearch,Db3_reclen+1);
- Move(dbrec^,dbsearch^,Db3_reclen);
-
- Db3_Seekbof;
-
- found:=False;
- WHILE NOT(found OR Db3_eof OR (Db3_ernr<>0)) DO
- BEGIN
- Db3_readnext;
-
- i:=0;
- match:=true;
- WHILE (i<Db3_reclen) AND match DO
- BEGIN
- IF (dbsearch^[i]<>#32)
- THEN
- CASE cs OF
- TRUE : match:=( dbsearch^[i] = dbrec^[i]);
- FALSE : match:=(Upcase(dbsearch^[i])=Upcase(dbrec^[i]));
- END;
- INC(i);
- END;
- found:=match;
- END;
-
- Db3_findfirst:=found;
-
- IF (found=False)
- THEN
- BEGIN
- Freemem(dbsearch,Db3_reclen+1);
- dbsearch:=NIL;
- END;
- END; {of Db3_findfirst}
-
- {---------------------------------------------------------}
-
- FUNCTION Db3_findnext(cs : BOOLEAN) : BOOLEAN;
-
- VAR
- match,
- found : BOOLEAN;
- i : INTEGER;
-
- BEGIN
- IF (dbsearch=NIL)
- THEN Seternr(18);
-
- found:=False;
- WHILE NOT(found OR Db3_eof OR (Db3_ernr<>0)) DO
- BEGIN
- Db3_readnext;
-
- i:=0;
- match:=true;
- WHILE (i<Db3_reclen) AND match DO
- BEGIN
- IF (dbsearch^[i]<>#32)
- THEN
- CASE cs OF
- TRUE : match:=( dbsearch^[i] = dbrec^[i]);
- FALSE : match:=(Upcase(dbsearch^[i])=Upcase(dbrec^[i]));
- END;
- INC(i);
- END;
- found:=match;
- END;
-
- Db3_findnext:=found;
-
- If (found=False) AND (dbsearch<>NIL)
- Then
- BEGIN
- Freemem(dbsearch,Db3_reclen+1);
- dbsearch:=NIL;
- END;
- END; {of Db3_findnext}
-
- {---------------------------------------------------------}
-
- FUNCTION Db3_soundex(name : STRING) : STRING;
-
- VAR
- work : STRING;
- code : CHAR;
- i,j : INTEGER;
-
- {---------------------------------------------------------}
-
- FUNCTION Encode(VAR c: CHAR): CHAR;
-
- BEGIN
- CASE Upcase(c) OF
- 'B','F','P','V': encode:='1';
- 'C','G','J','K','Q','S','X','Z': encode:='2';
- 'D','T': encode:='3';
- 'L': encode:='4';
- 'M','N': encode:='5';
- 'R': encode:='6';
- 'A','E','I','O','U','Y': encode:='7';
- 'H','W': encode:='8';
- ELSE encode:=' ';
- END;
- END; {of Encode}
-
- {---------------------------------------------------------}
-
- BEGIN
- {----If we can't calculate, this is the answer}
- work:='';
-
- {----Skip all non alpha codes in front}
- i:=1;
- WHILE (i<=Length(name)) AND (Encode(name[i])=' ') DO Inc(i);
-
- {----If any alpha characters left, start calculating the SOUNDEX code}
- IF (i<=Length(name))
- THEN
- BEGIN
- {----The first alpha letter of string is the first letter of the code}
- work:=Upcase(name[i]);
- Inc(i);
-
- {----Be sure while loop precondition is correct}
- j:=1;
- code:=#00;
-
- {----Calculate the numeric part of the code, }
- { with a maximum of 3 digits, stop if a non }
- { alpha character is encountered }
- WHILE (i<=Length(name)) AND (j<=3) AND (code<>' ') DO
- BEGIN
- code:=Encode(name[i]);
-
- {----If new code group then add the goup number}
- IF (code IN ['1'..'6']) AND (work[j]<>code)
- THEN
- BEGIN
- Inc(j);
- work:=work+code;
- END;
- Inc(i);
- END;
- END;
-
- {----Return the resulting SOUNDEX code}
- Db3_soundex:=work;
-
- END; {of Db3_soundex}
-
- {---------------------------------------------------------}
-
- FUNCTION Db3_firstsoundex(no : INTEGER;s : STRING) : BOOLEAN;
-
- VAR
- found : BOOLEAN;
- sdx : STRING;
-
- BEGIN
- Db3_Seekbof;
-
- sdx:=Db3_soundex(s);
-
- found:=False;
- WHILE NOT(found OR Db3_eof OR (Db3_ernr<>0)) DO
- BEGIN
- Db3_readnext;
- found:=(Pos(sdx,Db3_field2soundex(no))=1);
- END;
-
- Db3_firstsoundex:=found;
- END; {of Db3_firstsoundex}
-
- {---------------------------------------------------------}
-
- FUNCTION Db3_nextsoundex(no : INTEGER; s : STRING) : BOOLEAN;
-
- VAR
- found : BOOLEAN;
- sdx : STRING;
-
- BEGIN
- sdx:=Db3_soundex(s);
-
- found:=False;
- WHILE NOT(found OR Db3_eof OR (Db3_ernr<>0)) DO
- BEGIN
- Db3_readnext;
- found:=(Pos(sdx,Db3_field2soundex(no))=1);
- END;
-
- Db3_nextsoundex:=found;
- END; {of Db3_nextsoundex}
-
- {---------------------------------------------------------}
-
- PROCEDURE Db3_sort(no : INTEGER);
-
- VAR
- dbsort : ^rectyp;
- swapped : BOOLEAN;
- i,j,l,r : LONGINT;
- s1,s2 : STRING;
- typ : CHAR;
-
- {---------------------------------------------------------}
-
- PROCEDURE Swap(r1,r2 : LONGINT);
-
- BEGIN
- {----Side Effects}
- i:=j;
- swapped:=True;
-
- {----the Swapping itself}
- Db3_replace(r1);
- Move(dbsort^,dbrec^,Db3_reclen);
- Db3_replace(r2);
- END; {of Swapped}
-
- {---------------------------------------------------------}
-
- FUNCTION Compare(VAR c1,c2 : STRING) : BOOLEAN;
-
- VAR
- i : INTEGER;
- s : STRING;
-
- BEGIN
- CASE typ OF
- 'M',
- 'N' : BEGIN
- {----Insert spaces for correct numeric compare}
- FOR i:=1 TO Db3_fieldlen(no)-Length(c1) DO Insert(#32,c1,i);
- FOR i:=1 TO Db3_fieldlen(no)-Length(c2) DO Insert(#32,c2,i);
- END;
- 'L',
- 'S',
- 'C' : BEGIN
- {----Convert to Uppercase for correct alpha compare}
- FOR i:=1 TO Length(c1) Do c1[i]:=Upcase(c1[i]);
- FOR i:=1 TO Length(c2) Do c2[i]:=Upcase(c2[i]);
- END;
- 'D' : ;
- END;
-
- {----Return TRUE if c2>c1}
- Compare:=(c2>c1);
- END; {of Compare}
-
- {---------------------------------------------------------}
-
- BEGIN
- {----Use ShakerSort on almost sorted *.DBF file}
- Getmem(dbsort,Db3_reclen+1);
- Move(dbrec^,dbsort^,Db3_reclen);
-
- l:=2;
- r:=Db3_filesize;
- i:=r-1;
-
- swapped:=TRUE;
- typ :=Db3_fieldtype(no);
-
- WHILE (l<=r) AND swapped DO
- BEGIN
- swapped:=False;
-
- {----Bubble Up}
- FOR j:=r DOWNTO l DO
- BEGIN
- {----Fetch record j-1 & save it}
- Db3_read(j-1);
- s2:=Db3_field2str(no);
- Move(dbrec^,dbsort^,Db3_reclen);
-
- {----Fetch record j}
- Db3_read(j);
- s1:=Db3_field2str(no);
-
- {----Bubble}
- IF Compare(s1,s2)
- THEN Swap(j-1,j);
- END;
- l:=i+1;
-
- {----Bubble Down}
- IF swapped
- THEN
- BEGIN
- FOR j:=l TO r DO
- BEGIN
- {----Fetch record j-1 & save it}
- Db3_read(j-1);
- s2:=Db3_field2str(no);
- Move(dbrec^,dbsort^,Db3_reclen);
-
- {----Fetch record j}
- Db3_read(j);
- s1:=Db3_field2str(no);
-
- {----Bubble}
- IF Compare(s1,s2)
- THEN Swap(j-1,j);
- END;
- r:=i-1;
- END;
- END;
-
- Freemem(dbsort,Db3_reclen+1);
-
- Db3_seekbof;
- END; {of Db3_sort}
-
- {---------------------------------------------------------}
-
- BEGIN
- db3_ernr :=0;
- db3_fatal:=False;
- dbsearch :=NIL;
- dbrec :=NIL;
- END.
-
-
- { DOCUMENTATION }
-
- Db3_01.PAS is written by
-
- Ir. G.W. van der Vegt
- Hondbroek 57
- 6121 XB Born (L)
-
- and uploaded as public domain software because the author likes to
- share it with other Turbo Pascal Users. Please keep the source the
- way it is and write extentions as separate units.
-
- This unit provides read/write access to Dbase III (Plus) *.DBF files. The
- unit is uploaded as it is, the author is not responsible for any damgage
- by programs using this module. The unit is, of course, tested.
-
- Before using any of the Db3 routine a program shall call Db3_open to
- initialize the file internal buffers & info. When finishing the program
- should call Db3_close to close the file & cleanup the internal buffer.
-
- All routines are documented so there's not much to say about them. Access
- to the DBF file is only allowed through this unit, so the file record
- isn't exported.
-
- Records must be read by Db3_read or Db3_readnext, and written by Db3_append
- or Db3_replace. All record functions use LONGINTs as parameter for addressing
- records in the file.
-
- When a record is read, one can read the field in the record by using the
- record number as parameter of the Db3_field2 procedures. This record
- number lies between 1 and maxfield. If one 's to be independend of the
- location of the record the Db3_fieldno can be used to convert a field
- name to the field number.
-
- When writing records fill all field with Db3_2field routines and don't
- forget to use Db3_undelete to initialize the deleted marker. It's of
- course also possible to read a record, modify some field and replace it.
-
- The Db3_pack routine packs the file in-place, so no temp file is created.
-
- This unit can't create DBase III *.DBF files as it can't write the file
- header & fieldefinitions. It's also impossble to change the structure of
- a DBase III *.DBF database with it. This is done to keep the unit simple.
- Creating & modifing databases is much easier in Dbase III Language.
-
- This unit uses a special naming convention to be sure there's no
- confict with procedures from other units. All exported names have
- a three letter prefix Db3_. The 01 in the Unit name is a unique
- version number.